package com.iptech.gxt.widget.core.client;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
import com.iptech.gxt.messages.client.XApplicationTabPanelMessagesImpl;
import com.iptech.gxt.theme.blue.client.tabs.ApplicationTabPanelAppearance;
import com.iptech.gxt.theme.blue.client.tabs.ApplicationTabPanelAppearance.ApplicationTabPanelResource;
import com.iptech.gxt.widget.core.client.event.PinEvent;
import com.iptech.gxt.widget.core.client.event.PinEvent.HasPinHandler;
import com.iptech.gxt.widget.core.client.event.PinEvent.PinHandler;
import com.sencha.gxt.core.client.Style.Side;
import com.sencha.gxt.core.client.dom.XElement;
import com.sencha.gxt.core.client.util.Margins;
import com.sencha.gxt.widget.core.client.TabItemConfig;
import com.sencha.gxt.widget.core.client.TabPanel;
import com.sencha.gxt.widget.core.client.menu.Menu;
import com.sencha.gxt.widget.core.client.menu.MenuItem;

public class ApplicationTabPanel extends TabPanel implements HasPinHandler, PinHandler{

	private boolean pinAsAppTab = false;
	private boolean applicationTabTooltip = true;
	private ApplicationTabPanelMessages applicationTabPanelMessages;
	private Widget widgetToPinAsAppTab;
	private LinkedHashMap<Widget, TabItemConfig> appTabItemConfigMap = new LinkedHashMap<Widget, TabItemConfig>();
	private final MenuItem pinAsAppTabMenuItem = new MenuItem(getApplicationTaPanelMessages().pinAsAppTab(), new SelectionHandler<MenuItem>() {
        @Override
        public void onSelection(SelectionEvent<MenuItem> event) {
        	pinAsAppTab(widgetToPinAsAppTab);
        }
	});
	
	public interface ApplicationTabPanelMessages {
	    String pinAsAppTab();
	}

	protected class DefaultApplicationTabPanelMessages implements ApplicationTabPanelMessages {

		@Override
		public String pinAsAppTab() {
			return XApplicationTabPanelMessagesImpl.getMessages().tabPanelItem_pinAsAppTab();
		}
	}
	
	@Override
	protected void onResize(int width, int height) {
		super.onResize(width, height);
		updateTabStripWrapSize();
	}
	
	private void updateTabStripWrapSize(){
		XElement bar = appearance.getBar(getElement());
		XElement stripWrap = appearance.getStripWrap(getElement());
		XElement appTabStripWrap = ((ApplicationTabPanelAppearance)appearance).getAppTabStripWrap(getElement());
		
		int w = 0;
		for(Entry<Widget, TabItemConfig> entry : appTabItemConfigMap.entrySet()){
			int index = getWidgetIndex(entry.getKey());
			XElement item = findItem(index);
			w += (item.getWidth(false) + item.getMargins(Side.LEFT));
		}
		
		if(bar.getWidth(true) > 0){
			appTabStripWrap.setWidth(width);
			if(!((ApplicationTabPanelAppearance)appearance).isScrolling(getElement())){
				stripWrap.setWidth(bar.getWidth(true) - w);
			}else{
				stripWrap.setWidth(bar.getWidth(true) - (w + 36));
			}
			
		}
	}
	
	private void pinAsAppTab(Widget w) {
		
		ApplicationTabPanelAppearance appearance = (ApplicationTabPanelAppearance) this.appearance;
		
		XElement stripWrap = appearance.getStripWrap(getElement());
		XElement appTabStripWrap = ((ApplicationTabPanelAppearance)appearance).getAppTabStripWrap(getElement());
		int index = getWidgetIndex(w);
		TabItemConfig config = getConfig(w);
		XElement item = findItem(index);
		
		updateItemToPin(item, config, w);
		updateStripElmsHeight(appTabStripWrap, stripWrap);

		appTabItemConfigMap.put(w, config);
		appearance.move(appearance.getAppTabStripWrap(getElement()), findItem(index), appTabItemConfigMap.size()-1);
		getContainer().insert(w, appTabItemConfigMap.size()-1);
		
		setActiveWidget(w);
		
		addPinHandler(this);
		fireEvent(new PinEvent());
		
	}
	
	private void updateStripElmsHeight(XElement appTabStripWrap, XElement stripWrap){
		XElement appTabStrip = ((ApplicationTabPanelAppearance)appearance).getChildStrip(appTabStripWrap);
		XElement strip = ((ApplicationTabPanelAppearance)appearance).getChildStrip(stripWrap); 
		int computedStripHeight = Math.max(appTabStrip.getHeight(true), strip.getHeight(true));
		appTabStrip.setHeight(computedStripHeight);
		strip.setHeight(computedStripHeight);
	}
	
	private void updateItemToPin(XElement item, TabItemConfig config, Widget w){
		config.setClosable(false);
		if(config.getIcon()== null){
			config.setIcon(ApplicationTabPanelResource.INSTANCE.defaultAppTabItemIcon());
		}
		update(w, config);	
		appearance.setItemWidth(item, getAppTabWidth(item));
	}
	
	private int getAppTabWidth(XElement item){
		int itemMarginLeft = item.getMargins(Side.LEFT);
		int tabRightPaddingLeft = ((ApplicationTabPanelAppearance)appearance).getTabRight(item).getPadding(Side.LEFT);
		int tabStripTextPaddingLeft = ((ApplicationTabPanelAppearance)appearance).getTabStripText(item).getPadding(Side.LEFT);
		
		return itemMarginLeft + tabRightPaddingLeft + tabStripTextPaddingLeft;
	}
	
	public void setPinAsApplicationTabMenu(boolean pinAsAppTab){
		this.pinAsAppTab = pinAsAppTab;
		disableContextMenu = true;
		if(pinAsAppTab){
			sinkEvents(Event.ONCONTEXTMENU);
		}
	}
	
	@Override
	protected void onItemContextMenu(Widget item, int x, int y) {
		super.onItemContextMenu(item, x, y);
		if(pinAsAppTab){
			if(closeContextMenu == null){
				closeContextMenu = new Menu();
			}
			widgetToPinAsAppTab = item;
			closeContextMenu.insert(pinAsAppTabMenuItem, closeContextMenu.getWidgetCount());
			closeContextMenu.showAt(x, y);
		}
	}
	
	@Override
	protected int itemIndex(Element item) {
		NodeList<Element> stripWrapItems = appearance.getStripWrap(getElement()).select(appearance.getItemSelector());
		NodeList<Element> appStripWrapItems = ((ApplicationTabPanelAppearance)appearance).getAppTabStripWrap(getElement()).select(appearance.getItemSelector());
		
		for (int i = 0; i < appStripWrapItems.getLength(); i++) {
		  if (appStripWrapItems.getItem(i) == item) {
		    return i;
		  }
		}
		
		for (int i = 0; i < stripWrapItems.getLength(); i++) {
	      if (stripWrapItems.getItem(i) == item) {
	    	  if(appStripWrapItems.getLength() > 1){
	    		  return i + (appStripWrapItems.getLength() -1);
	    	  }else{
	    		  return i;
	    	  }
	      }
	    }
	    return -1;
	}
	
	@Override
	protected XElement findItem(int index) {
		List<Element> items = new ArrayList<Element>();
		if(appTabItemConfigMap.size()>0){
			NodeList<Element> elms = ((ApplicationTabPanelAppearance)appearance).getAppTabStripWrap(getElement()).select(appearance.getItemSelector());
			Element tabEdgeElm = appearance.getStripEdge(((ApplicationTabPanelAppearance)appearance).getAppTabStripWrap(getElement()));
			for(int i=0; i<elms.getLength(); i++){
				Element elm = elms.getItem(i);
				if(!elm.equals(tabEdgeElm))
					items.add(elm);
			}
		}
		
		NodeList<Element> elms = appearance.getStripWrap(getElement()).select(appearance.getItemSelector());
		for(int i=0; i<elms.getLength(); i++){
			Element elm = elms.getItem(i).cast();
			items.add(elm);
		}
		
		return items.get(index).cast();
		
	}
	
	@Override
	public void add(Widget widget, TabItemConfig config) {
		int widgetIndex = getWidgetCount();
		int itemIndex = getWidgetCount()-appTabItemConfigMap.size();
	    
		insert(widget,itemIndex, config);
	    getContainer().insert(getContainer().getWidget(itemIndex), widgetIndex + 1);
	    if (getActiveWidget() == null && isAutoSelect()) {
	    	setActiveWidget(widget);
	    }
	    
	    updateTabStripWrapSize();
	}
	
	@Override
	public boolean remove(Widget child) {
		boolean result = super.remove(child);
		if(appTabItemConfigMap.containsKey(child)){
			appTabItemConfigMap.remove(child);
		}
		return result;
	}
	

	public ApplicationTabPanelMessages getApplicationTaPanelMessages() {
		if (applicationTabPanelMessages == null) {
			applicationTabPanelMessages = new DefaultApplicationTabPanelMessages();
		}
		return applicationTabPanelMessages;
	}

	public void setApplicationTabPanelMessages(ApplicationTabPanelMessages applicationTabPanelMessages) {
		this.applicationTabPanelMessages = applicationTabPanelMessages;
	}
	
	@Override
	public void onBrowserEvent(Event event) {
		super.onBrowserEvent(event);
		if(event.getTypeInt() == Event.ONMOUSEOVER && applicationTabTooltip){
			((ApplicationTabPanelAppearance)appearance).onAppItemMouseOver(getElement(),event);
		}
	}

	public void setApplicationTabTooltip(boolean b) {
		applicationTabTooltip = b;
	}

	@Override
	public HandlerRegistration addPinHandler(PinHandler handler) {
		return addHandler(handler, PinEvent.getType());
	}

	@Override
	public void onPin(PinEvent event) {
		updateTabStripWrapSize();
		updateTabStripWrapMargins();
	}
	
	private void updateTabStripWrapMargins(){
		XElement stripWrap = appearance.getStripWrap(getElement());
		if(((ApplicationTabPanelAppearance)appearance).isScrolling(getElement())){
			Margins margins = new Margins();
			margins.setLeft(stripWrap.getMargins(Side.LEFT) + 30);
			margins.setRight(stripWrap.getMargins(Side.RIGHT));
			
			stripWrap.setMargins(margins);
		}
	}

}
